import {stringUtils} from "../../utils/stringUtils";
import {ConstVariable} from "../support/ConstVariable";
import {assert} from "../../utils/assert";
import {loggerManager, LOG_LEVEL} from "../../utils/Log4js";
import {ICPlayerProvider} from "../providers/ICPlayerProvider";
import {MidwayProvider} from "../providers/MidwayProvider";
import {supportFunction} from "../../utils/supportFunction";
import coursewareConfigManager from "../managers/CoursewareConfigManager";
import i18nManager from "../managers/I18nManager";
import styleManager from "../managers/StyleManager";
import jQuery from 'jquery';

@ICPlayerProvider.ConstructorAdapter()
@MidwayProvider.ConstructorAdapter()
class ModuleBase {
    constructor(clazz = "unknown", interfaceObj = undefined) {
        this._basePath = "/";
        this._queryString = {};
        this._playerController = null;
        this._logger = null;
        this._interface = {};
        this._clazz = clazz;
        this._environment = {
            isApp: false,
            isWeb: true,
            isPC: false,
            isTeacher: false,
            isStudent: false
        };
        //模块的视图
        this._view = null;
        //模块的模型
        this._model = null;
        //模块的注入模型
        this._injectModel = null;
        //自定义配置模型
        this._customConfigModel = null;
        this._currentLanguage = 'zh_CN';
        this._app = undefined;
        this.metaInfo = {
            name: "",
            type: ConstVariable.PresenterType.FUNCTIONAL,
        };
        this._CLASS_ID_ = stringUtils.randomWord(false, 16);  //类的唯一ID
        //如果容器注入对象不为空
        if (interfaceObj) {
            jQuery.extend(true, this._interface, interfaceObj);
        }
        this._init();
    }

    get MetaInfo() {
        return this.metaInfo;
    }

    get Logger() {
        return this._logger;
    }

    /**
     * @return {string}
     */
    get BasePath() {
        return this._basePath;
    }

    get PlayerController() {
        return this._playerController;
    }

    get QueryString() {
        return this._queryString;
    }

    get Environment() {
        return this._environment;
    }

    get View() {
        return this._view;
    }

    get Model() {
        return this._model;
    }

    get InjectModel() {
        return this._injectModel;
    }

    get CustomConfig() {
        return this._customConfigModel;
    }

    get Language() {
        return this._currentLanguage;
    }

    setPlayerController(controller) {
        assert(controller === undefined, "player controller is null");
        assert(controller.require === undefined, "player controller not contain require method");
        assert(controller.getEventBus === undefined, "player controller not contain getEventBus method");
        this._playerController = controller;
    }

    setBasePath(path) {
        this._basePath = path !== undefined ? path : "/";
    }

    setUrlParams(params) {
        this._queryString = params;
        this._currentLanguage = params["_lang_"] || "zh_CN";
        if (this._queryString["app"]) {
            this._app = this._queryString["app"];
        } else if (this._queryString["sys"]) {
            this._app = this._queryString["sys"];
        }
    }

    /**
     * 模块加载的入口
     */
    run(...args) {
        this._view = args[0][0] || undefined;
        this._model = args[0][1] || undefined;
        this._injectModel = args[0][2] || undefined;
        this._customConfigModel = coursewareConfigManager.getConfig(this.metaInfo.coursewareObject || this.metaInfo.name);
        //在run的时候调用实例化颗粒服务的过程
        this._initModuleService();
    }

    /**
     * 模块销毁时调用的方法
     */
    destroy() {
        this.removeEventListener();
        this.$release();
    }

    /**
     * 获取当前模块使用的皮肤
     * @returns {string} 皮肤类型
     */
    getSkin() {
        return 'wood';
    }

    /**
     *
     * @param app
     * @returns {boolean}
     */
    embedApplication(app) {
        if (this.QueryString) {
            let sysApp = this.QueryString["sys"] !== undefined ? this.QueryString["sys"] :
                (this.QueryString["app"] !== undefined ? this.QueryString["app"] : "unknown");
            return sysApp === app;
        }
        return false;
    }

    /**
     * 添加事件监听器
     * @param name
     * @param type
     * @param callback
     */
    @ICPlayerProvider.MethodAdapter()
    @MidwayProvider.MethodAdapter()
    addEventListener() {
        return -1;
    }

    /**
     * 移除所有事件监听器
     */
    @ICPlayerProvider.MethodAdapter()
    @MidwayProvider.MethodAdapter()
    removeEventListener() {
        return -1;
    }

    /**
     * 广播一个事件
     * @param name
     * @param type
     * @param data
     * @returns {*}
     */
    @ICPlayerProvider.MethodAdapter()
    @MidwayProvider.MethodAdapter()
    dispatchEvent(name, type, data) {
        return -1;
    }

    /**工具类方法**/
    /**
     * 动态加载模块
     * @returns {*|JQueryDeferred<T>}
     */
    @ICPlayerProvider.MethodAdapter()
    @MidwayProvider.MethodAdapter()
    requireComponent() {
        // name, properties, rendTo, layout
        const options = arguments[0], deffer = jQuery.Deferred();
        this.PlayerController.require(options).done(function (module) {
            if (module._handleOver_) {
                let pending = [];
                for(let key in module._handleOver_) {
                    pending.push(module._handleOver_[key]);
                }
                jQuery.when.apply($, pending).done(() => {
                    deffer.resolve(module);
                });
            } else {
                deffer.resolve(module);
            }
        });
        return deffer;
    }

    //创建代理方法
    createDelegate(fn, args, isAppendArgs, scope, exceptionHandler) {
        return function () {
            //如果创建的时候没有输入参数，使用调用的参数
            let callArgs = args || arguments;
            if (isAppendArgs === true) {
                //arguments数组化
                callArgs = Array.prototype.slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }
            try {
                return fn.apply(scope || window, callArgs);
            } catch (e) {
                if (jQuery.isFunction(exceptionHandler)) {
                    return exceptionHandler(e);
                } else {
                    throw e;
                }
            }
        };
    }

    //顺序执行方法
    runSequence(fnConfigs, name) {
        return supportFunction.runSequence(fnConfigs, name);
    }

    /***********/

    //==子类需要重写或实现的方法
    /**
     * 提供给子类生命周期入口方法
     * @param options 加载参数,可变值
     */
    $launch(options) {
    }

    /**
     * 提供给子类生命周期销毁方法
     */
    $release() {
    }

    //==子类需要实现的方法结束

    //私有方法开始
    //类初始化方法
    @ICPlayerProvider.MethodAdapter()
    @MidwayProvider.MethodAdapter()
    _init() {
        if (this.metaInfo) {
            this.metaInfo = jQuery.extend(this.metaInfo, {_CLASS_ID_: this._CLASS_ID_});
        } else {
            this.metaInfo = {_CLASS_ID_: this._CLASS_ID_};
        }
        this._logger = loggerManager().get(this._clazz ? this._clazz : this.metaInfo.name);
        //添加默认日志Handler
        this.Logger.appendHandler(defaultLoggerHandle, {level: LOG_LEVEL.DEBUG});
    }

    _trimSlash() {
        let basePath = this.BasePath;
        if (basePath && basePath.length > 1 && basePath[basePath.length - 1] === "/") {
            basePath = basePath.substr(0, basePath.length - 1);
        }
        return basePath;
    }

    //初始化颗粒服务
    _initModuleService() {
        //对注入到当前对象中的服务类进行统一的实例化
        if (this.__ModuleServices !== undefined) {
            const me = this;
            jQuery.each(this.__ModuleServices, function (key, value) {
                if (!me[key]) {
                    if (value.hasFilter) {
                        //如果对象是一个函数
                        const clazz = value.filter.call(me);
                        me[key] = clazz !== undefined ?
                            new window["__ServiceComponent"][value.namespace][clazz] :
                            undefined;
                    } else {
                        //如果对象是一个类
                        me[key] = new value.clazz();
                    }
                    if (me[key]["setContext"]) {
                        me[key]["setContext"].call(me[key], me);
                    }
                }
            });
        }
    }

    _loadI18nResource(langSet) {
        const langDef = jQuery.Deferred();
        i18nManager.loadLanguage(this.metaInfo.name, this.Language)
            .done((data) => {
                i18nManager.replaceView(this.View, data.lang);
                jQuery.extend(langSet, data.lang);
                langDef.resolve();
            })
            .fail(() => {
                console.error("load i18n resource error");
                langDef.reject();
            });
        return langDef.promise();
    }

    _loadStyleLibrary() {
        if (this.metaInfo.type === ConstVariable.PresenterType.LAUNCHER) {
            const skin = this.getSkin();
            const styleLib = this.metaInfo.styleLib || this.metaInfo.name;
            styleManager.loadStyle(styleLib, this._app, skin, this.Language);
        }
    }

    _releaseStyleLibrary() {
        if (this.metaInfo.type === ConstVariable.PresenterType.LAUNCHER) {
            styleManager.releaseStyle(this.metaInfo.styleLib || this.metaInfo.name);
        }
    }
}

function defaultLoggerHandle(message, context) {
    switch (context.level.name) {
        case 'DEBUG':
            console.debug(message);
            break;
        case 'INFO':
            console.info(message);
            break;
        case 'WARN':
            console.warn(message);
            break;
        case 'ERROR':
            console.error(message);
            break;
        default:
            console.log(message);
            break;
    }
}

export {ModuleBase};